using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Campus
{
    public class HUD
    {

        #region Fields

        /// <summary>
        /// This constant represents the number of characters allowed per line in the Unit Info portion of the HUD.
        /// </summary>
        private const int UNITINFOWRAP = 60;

        /// <summary>
        /// This contact represents the number of characters allowed per line in the Player Messages Box portion of the HUD.
        /// </summary>
        private const int PLAYERMESSAGEBOXWRAP = 38;

        /// <summary>
        /// Holds the information overlays to be used in the HUD
        /// </summary>      
        private Dictionary<String, InformationOverlay> m_informationOverlays =
            new Dictionary<String, InformationOverlay>();
        private bool m_isVisible = false;
        public bool IsVisible
        {
            get { return m_isVisible; }
            set { m_isVisible = value; }
        }
        #endregion

        #region Constructors
        public HUD()
        {

        }
        public HUD(Dictionary<String, InformationOverlay> informationOverlays)
        {
            this.m_informationOverlays = informationOverlays;
        }
        #endregion

        #region Other Functions
        /// <summary>
        /// Adds an information overlay to the HUD
        /// </summary>
        /// <param name="name">The name corresponding to this information overlay</param>
        /// <param name="overlay">The information overlay</param>
        public void AddInformationOverlay(String name, InformationOverlay overlay)
        {
            this.m_informationOverlays.Add(name, overlay);
        }

        /// <summary>
        /// Removes an information overlay from the HUD
        /// </summary>
        /// <param name="name">The name of the information overlay to remove</param>
        public void RemoveInformationOverlay(String name)
        {
            this.m_informationOverlays.Remove(name);

        }

        /// <summary>
        /// Gets an information overlay from the HUD
        /// </summary>
        /// <param name="name">The name of the information overlay to return</param>
        /// <returns>NULL if the information overlay of the given name does not exist, 
        /// or the information overlay specified</returns>
        public InformationOverlay GetInformationOverlay(String name)
        {
            if (m_informationOverlays.ContainsKey(name))
            {
                return m_informationOverlays[name];
            }
            return null;
        }

        public void ChangeVisibility()
        {
            m_isVisible = !m_isVisible;
        }
        
        public void Update(Player player)
        {
            if(this.GetInformationOverlay("pizzaInfo") != null)
            {
                this.GetInformationOverlay("pizzaInfo").ModifyInformation("foodInfo", player.UsedFood +"/" + player.MaxFood);
            }
            if (this.GetInformationOverlay("researchInfo") != null)
            {
                this.GetInformationOverlay("researchInfo").ModifyInformation("researchInfo", "" + player.Research);
            }
            if (this.GetInformationOverlay("moneyInfo") != null)
            {
                this.GetInformationOverlay("moneyInfo").ModifyInformation("moneyInfo", "" + player.Money);
            }
            if (this.GetInformationOverlay("unitInfo") != null)
            {
                InformationOverlay hudUnitInfo = this.GetInformationOverlay("unitInfo");

                if (player.Selected.Count == 1 && player.CurrentUnit.IsUsable)
                {
                    hudUnitInfo.ModifyInformation("unitInfo", "" + Utilities.WordWrap(player.CurrentUnit.ToString(), UNITINFOWRAP, false));
                }
                else
                    hudUnitInfo.ModifyInformation("unitInfo", "");
            }
            if (this.GetInformationOverlay("unitImage") != null)
            {
                // Clear out any previous data so we can rebuild it.
                ClearEntitySelectionComponent(player);

                // If one Unit/Structure is selected.
                if (player.Selected.Count == 1)
                {
                    BuildSingleEntitySelectionComponent(player);
                }
                // If multiple Units or Structures are selected.
                else if (player.Selected.Count > 1)
                {
                    BuildMultiEntitySelectionComponent(player);
                }
            }
            if (this.GetInformationOverlay("playerMessagesInfo") != null)
            {
                BuildPlayerMessagesComponent(player);
            }
        }
        /// <summary>
        /// Draws the HUD (by drawing all of its constituent information overlays
        /// </summary>
        public void Draw(SpriteBatch spriteBatch)
        {
            if (m_isVisible)
            {
                foreach (KeyValuePair<string, InformationOverlay> kvp in m_informationOverlays)
                {
                    kvp.Value.Draw(spriteBatch);
                }
            }
        }

        #region HUD "Work" Functions

        public void ClearEntitySelectionComponent(Player player)
        {
            // Clear the multi-selection images.
            for (int i = 0; i < 2; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    this.GetInformationOverlay("unitImage" + i + "" + j).Image = null;
                    this.GetInformationOverlay("unitHealthBarImage" + i + "" + j).ImageOpacity = (byte)0;
                }
            }
            // Clear the garrisoned units images.
            for (int i = 0; i < 8; i++)
                this.GetInformationOverlay("garrisonedUnitImage" + i).Image = null;
            // Clear the single selection image and health bar image.
            this.GetInformationOverlay("unitImage").Image = null;
            this.GetInformationOverlay("singleSelectionHealthBarImage").ImageOpacity = (byte)0;
            // Clear the building progress bar.
            this.GetInformationOverlay("structureBuildingBarImage").ImageOpacity = (byte)0;
            // Hide the structure-building information.
            this.GetInformationOverlay("constructingInfo").ModifyInformation("constructingInfo", "");
            this.GetInformationOverlay("constructingImage").ImageOpacity = (byte)0;
        }

        private void BuildSingleEntitySelectionComponent(Player player)
        {
            if (player.CurrentUnit.IsUsable)
            {
                this.GetInformationOverlay("singleSelectionHealthBarImage").ImageOpacity = (byte)255;
                this.GetInformationOverlay("unitImage").Image = player.CurrentUnit.EntitySelectedImage;

                float healthRatio = (float)player.CurrentUnit.CurrentHP / (float)player.CurrentUnit.MaxHP;
                Color healthBarColor = Color.Teal;

                if (healthRatio > .66 && healthRatio <= 1.0f)
                    healthBarColor = Color.Green;
                else if (healthRatio > .33 && healthRatio <= .66f)
                    healthBarColor = Color.Yellow;
                else if (healthRatio > 0 && healthRatio <= .33)
                    healthBarColor = Color.Red;

                this.GetInformationOverlay("singleSelectionHealthBarImage").Size = new Vector2(healthRatio * 45, 10);
                this.GetInformationOverlay("singleSelectionHealthBarImage").ImageColor = healthBarColor;
            }

            // If the selected Unit or Structure has the ability to Garrison, fill in those images.
            if (player.CurrentUnit.Abilities.ContainsKey("Garrison"))
            {
                List<Unit> garrisonedUnits = ((GarrisonAbility)player.CurrentUnit.Abilities["Garrison"]).GarrisonedUnits;

                for (int i = 0; i < 8; i++)
                {
                    if (i < garrisonedUnits.Count)
                    {
                        Unit currentUnit = garrisonedUnits[i];

                        this.GetInformationOverlay("garrisonedUnitImage" + i).Image = currentUnit.EntitySelectedImage;
                    }
                }
            }

            // If it's a structure building something, show/fill in the construction bar
            if (player.CurrentUnit is Structure && player.CurrentUnit.PlayerOwner == player)
            {
                if (player.CurrentUnit.AbilityQueue.Count > 0)
                {
                    InformationOverlay progressBar = this.GetInformationOverlay("structureBuildingBarImage");

                    if (player.CurrentUnit.AbilityQueue.Peek() is BuildUnitAbility)
                    {
                        progressBar.ImageOpacity = (byte)255;

                        BuildUnitAbility unitBuilding = (BuildUnitAbility)player.CurrentUnit.AbilityQueue.Peek();
                        BuildRequirements.Requirements reqs = BuildRequirements.GetRequirements(unitBuilding.UnitType);

                        float progressRatio = (float)unitBuilding.ElapsedTime / (float)reqs.BuildTime;

                        progressBar.Size = new Vector2(progressRatio * 45, 10);
                    }
                }

                if (!player.CurrentUnit.IsUsable && player.CurrentUnit is BuildingStructure)
                {
                    this.GetInformationOverlay("constructingInfo").ModifyInformation("constructingInfo", "Constructing...");

                    InformationOverlay progressBar = this.GetInformationOverlay("constructingImage");
                    progressBar.ImageOpacity = (byte)255;

                    BuildingStructure selectedConstructionSite = (BuildingStructure)player.CurrentUnit;
                    BuildStructureAbility buildingAbility = selectedConstructionSite.OwningAbility;

                    float progressRatio = (float)buildingAbility.ElapsedTime / (float)buildingAbility.BuildTime;
                    progressBar.Size = new Vector2(progressRatio * 200, 25);
                }
            }
        }

        private void BuildMultiEntitySelectionComponent(Player player)
        {
            this.GetInformationOverlay("unitInfo").ModifyInformation("unitInfo", "");

            for (int i = 0; i < 2; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    if (i < 2 && (8 * i) + j < player.Selected.Count)
                    {
                        BaseEntity selectedEntity = player.Selected[(j * i) + j];

                        this.GetInformationOverlay("unitImage" + i + "" + j).Image = selectedEntity.EntitySelectedImage;

                        float healthRatio = (float)selectedEntity.CurrentHP / (float)selectedEntity.MaxHP;
                        Color healthBarColor = Color.Teal;

                        if (healthRatio > .66 && healthRatio <= 1.0f)
                            healthBarColor = Color.Green;
                        else if (healthRatio > .33 && healthRatio <= .66f)
                            healthBarColor = Color.Yellow;
                        else if (healthRatio > 0 && healthRatio <= .33)
                            healthBarColor = Color.Red;

                        InformationOverlay healthBarImage = this.GetInformationOverlay("unitHealthBarImage" + i + "" + j);

                        healthBarImage.ImageOpacity = (byte)255;
                        healthBarImage.Size = new Vector2(healthRatio * 45, 10);
                        healthBarImage.ImageColor = healthBarColor;
                    }
                }
            }
        }

        private void BuildPlayerMessagesComponent(Player player)
        {
            List<string> messages = player.HUDMessages;
            string newContent = "";

            if (messages.Count > 0)
            {
                for (int i = 0; i < messages.Count; i++)
                {
                    if (messages[i] != null)
                    {
                        newContent += Utilities.WordWrap(messages[i], PLAYERMESSAGEBOXWRAP, true) + "\n";
                    }
                }
            }

            this.GetInformationOverlay("playerMessagesInfo").ModifyInformation("playerMessagesInfo", newContent);

            // If there are no messages, then hide the message box.
            if (newContent.Equals(""))
                this.GetInformationOverlay("playerMessages").ImageOpacity = (byte)0;
            else
            {
                this.GetInformationOverlay("playerMessages").ImageOpacity = (byte)255;
                // Size the background box according to the number of lines currently onscreen
                this.GetInformationOverlay("playerMessages").Size = new Vector2(250, 15 * newContent.Split('\n').Length + 5);
            }
        }

        #endregion

        #endregion
    }


}